using System;
using System.Reflection;

using Db4objects.Db4o;
using Db4objects.Db4o.Config;
using Universum.Infrastructure.Configuration;
using Db4objects.Db4o.Ext;
using Sharpen.Lang;
using System.Web;

/*
 * ServerModule manages opening and closing of a db4o server:
 * - the server is opened on the first request
 * - the server is closed when the application is offloaded
 */

namespace Universum.Infrastructure.Utils
{
	public class Db4oServerModule
	{

		// static server variable 
		private static IObjectServer objectServer = null;
		private static readonly object lock_state = new object();
		/*
		 * Registers an alias for persistent classes namespace and assembly. The current assembly is temporary 
		 * and renamed after each recompilation, that is why it can not be used for persistence. An alias name is used 
		 * to persist the classes
		 */
		public static IConfiguration Configure()
		{
			Assembly assembly = Assembly.GetExecutingAssembly();
			String assemblyName = "Universum.Model.Domain.*";
			IConfiguration configuration = Db4oFactory.Configure();
			configuration.AddAlias(new WildcardAlias("Universum.Model.Domain.*, $safeprojectname$", assemblyName));
			configuration.OptimizeNativeQueries(true);
			configuration.UpdateDepth(7);
			configuration.LockDatabaseFile(false);
			//configuration.WeakReferences(false);
			//configuration.AutomaticShutDown(false);

			return configuration;
		}
		// end Configure

		/*
		 * Opens a server connection to the db4o database on a request
		*/
		public static IObjectServer Server
		{
			get
			{
				lock (lock_state)
				{
					if (objectServer == null)
					{
					retry_loading_server:
						try
						{

							if (HttpContext.Current.Application[ConstantIdentifiers.DB4O_FILE_NAME] == null)
							{
								objectServer = Db4oFactory.OpenServer(Configure(),
								   ConstantIdentifiers.DB4O_FILE_NAME,
								   0);

								HttpContext.Current.Application.Add(
									ConstantIdentifiers.DB4O_FILE_NAME,
									objectServer);
							}
							else
								objectServer = HttpContext.Current.Application[ConstantIdentifiers.DB4O_FILE_NAME] as IObjectServer;
						}
						catch (
							// only happens when appliation is restarted
							// and more than one connections comes
							// this way
							DatabaseFileLockedException)
						{
							// this is the first time I've used a 
							// goto statement but it's the last resort
							// hope to never do it again
							goto retry_loading_server;

						}
						if (objectServer == null) goto retry_loading_server;
					}
				}
				return objectServer;

			}
		}
		// end Server

		/*
		 *  Procedure to close the server connection
		 */
		public static void CloseServer()
		{
			if (objectServer != null)
			{
				objectServer.Close();
				HttpContext.Current.Application[ConstantIdentifiers.DB4O_FILE_NAME] = null;
			}

			objectServer = null;
		}
		// end CloseServer
	}
}